import { Injectable, Logger } from '@nestjs/common';
import Anthropic from '@anthropic-ai/sdk';
import {
  ContentBlockParam,
  MessageParam,
} from '@anthropic-ai/sdk/resources/messages';
import { ConfigService } from '@nestjs/config';
import { ChatCompletionResponseDto } from '../dto/completion-response.dto';
import { MultimodalCompletionRequestDto } from '../dto/multimodal-message.dto';
import { ImageAnalysisResponseDto } from '../dto/image-analysis-request.dto';

interface AnthropicContentBlock {
  type: string;
  text?: string;
}

@Injectable()
export class AnthropicService {
  private readonly logger = new Logger(AnthropicService.name);
  private readonly client: Anthropic;
  private readonly defaultModel = 'claude-3-7-sonnet-20250219';

  constructor(private configService: ConfigService) {
    const apiKey =
      this.configService.get<string>('ANTHROPIC_API_KEY') ||
      this.configService.get<string>('ai.anthropic.apiKey');

    if (!apiKey) {
      this.logger.warn(
        'Anthropic API key is not set. Please set ANTHROPIC_API_KEY in your environment variables.',
      );
    }

    this.client = new Anthropic({
      apiKey: apiKey || 'dummy_key_for_initialization',
    });
  }
  /**
   * 生成多模态聊天完成
   *
   * @param request 多模态完成请求
   * @returns 生成的响应
   */
  async generateMultimodalCompletion(
    request: MultimodalCompletionRequestDto,
  ): Promise<ChatCompletionResponseDto> {
    try {
      // 验证API密钥
      const apiKey =
        this.configService.get<string>('ANTHROPIC_API_KEY') ||
        this.configService.get<string>('ai.anthropic.apiKey');
      if (!apiKey) {
        throw new Error('Anthropic API key is not set');
      }

      // 创建新的 Anthropic 实例（直接使用 apiKey）
      const anthropic = new Anthropic({
        apiKey,
      });

      // 设置默认选项
      const model = request.model || this.defaultModel;
      const maxTokens = request.max_tokens || 1024;

      // 准备发送给Anthropic API的消息数组
      const anthropicMessages: MessageParam[] = [];

      for (const msg of request.messages) {
        const role = this.mapRole(msg.role);

        // 处理纯文本消息
        if (typeof msg.content === 'string') {
          anthropicMessages.push({
            role,
            content: msg.content,
          });
          continue;
        }

        // 处理多模态消息
        const contentBlocks: ContentBlockParam[] = [];

        for (const block of msg.content) {
          if (block.type === 'text') {
            contentBlocks.push({
              type: 'text',
              text: block.text,
            });
          } else if (block.type === 'image') {
            if (block.source.type === 'url') {
              contentBlocks.push({
                type: 'image',
                source: {
                  type: 'url',
                  url: block.source.url,
                },
              });
            } else if (block.source.type === 'base64' && block.source.data) {
              // 确保有media_type
              if (!block.source.media_type) {
                this.logger.warn(
                  'Base64 image source missing media_type, defaulting to image/jpeg',
                );
              }

              // 确保media_type是合法的值
              const mediaType = block.source.media_type || 'image/jpeg';
              // 仅接受Anthropic支持的媒体类型
              const validMediaType = [
                'image/jpeg',
                'image/png',
                'image/gif',
                'image/webp',
              ].includes(mediaType)
                ? mediaType
                : 'image/jpeg';

              contentBlocks.push({
                type: 'image',
                source: {
                  type: 'base64',
                  data: block.source.data,
                  media_type: validMediaType,
                },
              });
            }
          }
        }

        anthropicMessages.push({
          role,
          content: contentBlocks,
        });
      }

      // 创建请求
      const response = await anthropic.messages.create({
        model,
        max_tokens: maxTokens,
        messages: anthropicMessages,
        temperature: request.temperature,
        stop_sequences: request.stop_sequences,
      });

      // 映射到标准化响应格式
      return {
        model: response.model,
        message: {
          role: 'assistant',
          content: this.extractTextContent(response.content),
        },
        promptTokens: response.usage.input_tokens,
        completionTokens: response.usage.output_tokens,
        totalTokens: response.usage.input_tokens + response.usage.output_tokens,
        rawResponse: response,
      };
    } catch (error) {
      this.logger.error(
        `Error generating multimodal completion: ${error instanceof Error ? error.message : String(error)}`,
        error instanceof Error ? error.stack : undefined,
      );
      throw error;
    }
  }

  /**
   * 分析图片并返回结果
   *
   * @param imageUrl 图片URL
   * @param model 可选的模型名称
   * @param maxTokens 可选的最大生成令牌数
   * @returns 分析结果
   */
  async analyzeImage(
    imageUrl: string,
    model?: string,
    maxTokens?: number,
  ): Promise<ImageAnalysisResponseDto> {
    try {
      // 验证API密钥
      const apiKey =
        this.configService.get<string>('ANTHROPIC_API_KEY') ||
        this.configService.get<string>('ai.anthropic.apiKey');
      if (!apiKey) {
        throw new Error('Anthropic API key is not set');
      }

      // 创建新的 Anthropic 实例
      const anthropic = new Anthropic({
        apiKey: apiKey,
      });

      // 设置默认选项
      const modelName = model || this.defaultModel;
      const tokens = maxTokens || 1024;

      // 构建分析提示文本
      const promptText = `# 角色：小红书图片风格总结专家
  
  你是一个小红书图片风格总结专家，擅长分析和归纳各类小红书封面的设计特点。你具备敏锐的视觉审美能力，能够准确识别不同封面的设计风格、文字排版特点和视觉元素运用。你的专长在于将复杂的视觉设计元素分解为清晰的风格类别，并为每种风格命名，帮助用户理解和应用这些设计元素到自己的创作中。
  
  ## 任务：
  
  请分析用户提供的小红书封面图片，并完成以下任务：
  
  1. 为该封面风格起一个独特、贴切的名称
  2. 描述其设计风格特点，包括：
     - 色彩基调
     - 卡片结构
     - 留白处理方式
     - 背景设计
     - 整体情感氛围
     - 视觉语言一致性
     - 边框与分割线使用
  3. 描述其文字排版风格，包括：
     - 标题处理方式
     - 段落布局特点
     - 标点符号使用特色
     - 表情符号融入方式
     - 重点内容强调手法
     - 语言表达风格
     - 排版层级设计
  4. 描述其视觉元素风格，包括：
     - 装饰角色特点
     - 表情元素多样性
     - 场景化呈现方式
     - 实物与图形结合手法
     - 装饰元素使用
     - 视觉元素位置布局
     - 概念可视化处理方式
       确保你的描述准确、具体，能帮助用户理解并复制这种风格的关键特征。
  
  ## 目标：
  1. 确保风格描述保持通用性，不要包含特定图片的具体内容或示例，避免在设计风格、文字排版风格和视觉元素风格中夹杂原图片中的文字和表述。
  2. 所有风格描述应该是可应用于多种内容的通用模板，而非针对单一图片的具体分析。
  
  ## 格式规范：
  严格按照如下 JSON 格式输出：
  {
  "Image_style_name": "<图片风格名称>",
  "Design_style": "<设计风格>",
  "Text_typesetting_style": "<文字风格>",
  "Visual_Element_Style": "<视觉元素风格>"
  }`;

      // 创建请求
      const response = await anthropic.messages.create({
        model: modelName,
        max_tokens: tokens,
        messages: [
          {
            role: 'user',
            content: [
              {
                type: 'image',
                source: {
                  type: 'url',
                  url: imageUrl,
                },
              },
              {
                type: 'text',
                text: promptText,
              },
            ],
          },
        ],
      });

      // 提取文本内容
      const content = this.extractTextContent(response.content);

      // 尝试解析JSON
      let result = content;
      try {
        // 如果返回的内容不是纯JSON，尝试提取JSON部分
        const jsonMatch = content.match(/\{[\s\S]*\}/);
        if (jsonMatch) {
          result = jsonMatch[0];
        }
      } catch (error) {
        this.logger.warn('Failed to extract JSON from response', error);
      }

      return {
        result,
        rawResponse: response,
      };
    } catch (error) {
      this.logger.error(
        `Error analyzing image: ${error instanceof Error ? error.message : String(error)}`,
        error instanceof Error ? error.stack : undefined,
      );
      throw error;
    }
  }

  /**
   * Map our standard role names to Anthropic's role names
   *
   * @param role The role to map
   * @returns The mapped role
   */
  private mapRole(role: string): 'user' | 'assistant' {
    switch (role.toLowerCase()) {
      case 'user':
        return 'user';
      case 'assistant':
        return 'assistant';
      case 'system':
        return 'user';
      default:
        return 'user';
    }
  }

  /**
   * 从Anthropic响应内容中提取文本
   * @param content Anthropic响应内容
   * @returns 提取的文本内容
   */
  private extractTextContent(content: AnthropicContentBlock[]): string {
    // 如果内容数组不为空，并且第一个元素的类型是文本，则返回文本内容
    if (content.length > 0 && content[0].type === 'text' && content[0].text) {
      return content[0].text;
    }
    // 否则返回整个内容的JSON字符串
    return JSON.stringify(content);
  }
}
